package com.ethink.platform.controller.order;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.constant.ResponseCodeEnum;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.framework.common.web.BaseController;
import com.ethink.framework.common.web.context.SPRequestContextHolder;
import com.ethink.framework.common.web.response.CommonResponse;
import com.ethink.mdm.api.AccountFacade;
import com.ethink.mdm.api.component.MdmComponent;
import com.ethink.mdm.api.info.CompanyAndBankInfo;
import com.ethink.mdm.api.info.CurrencyInfo;
import com.ethink.order.api.SaleOrderFacade;
import com.ethink.order.api.enums.SaleOrderOrderStatusEnum;
import com.ethink.order.api.enums.SaleOrderOrderTypeEnum;
import com.ethink.order.api.info.SaleDetailOrderInfo;
import com.ethink.order.api.info.SaleOrderInfo;
import com.ethink.order.api.info.TobSaleDetailOrderInfo;
import com.ethink.order.api.model.SaleDetailOrderModel;
import com.ethink.order.api.model.SaleOrderModeQueryModel;
import com.ethink.order.api.model.SaleOrderPageQueryModel;
import com.ethink.order.api.request.*;
import com.ethink.order.api.response.SaleOrderAddResponse;
import com.ethink.order.api.response.SaleOrderDetailResponse;
import com.ethink.platform.common.properties.PlatformCommonProperties;
import com.ethink.platform.controller.order.info.ExportInfo;
import com.ethink.platform.controller.order.info.SaleOrderImportInfo;
import com.ethink.platform.manager.ExportManager;
import com.ethink.platform.manager.SaleOrderManager;
import com.ethink.system.api.SystemTodoFacade;
import com.ethink.system.api.enums.SystemTodoTodoTypeEnum;
import com.ethink.system.api.request.SystemTodoAddRequest;
import com.ethink.warehouse.api.LogisticsTraceApplyOrderFacade;
import com.ethink.warehouse.api.MateInventoryFacade;
import com.ethink.warehouse.api.SubWarehouseFacade;
import com.ethink.warehouse.api.enums.SubjectEnum;
import com.ethink.warehouse.api.info.MateInventoryDetailInfo;
import com.ethink.warehouse.api.info.SubWarehouseInfo;
import com.ethink.warehouse.api.request.LogisticsTraceApplyDeleteRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author default
 * @version 1.0.0
 * @ClassName SaleOrderController.java
 * @Description
 * @createTime 2022年11月22日 10:49:00
 */
@Tag(name = "SaleOrderController", description = "销售单 Controller")
@RestController
@Slf4j
@RequestMapping("platform-server/v1/order-service")
public class SaleOrderController extends BaseController {

    @Autowired
    private SaleOrderFacade saleOrderFacade;

    @Autowired
    private SaleOrderManager saleOrderManager;

    @Autowired
    private PlatformCommonProperties commonProperties;

    @Autowired
    private SystemTodoFacade systemTodoFacade;

    @Autowired
    private SubWarehouseFacade subWarehouseFacade;

    @Autowired
    private MateInventoryFacade mateInventoryFacade;

    @Autowired
    private AccountFacade accountFacade;

    @Autowired
    private MdmComponent mdmComponent;

    @Autowired
    private ExportManager exportManager;

    @Autowired
    private LogisticsTraceApplyOrderFacade logisticsTraceApplyOrderFacade;

    @Operation(summary = "新增")
    @PostMapping("/saleOrder/add")
    public CommonResponse addSaleOrder(@Validated @RequestBody SaleOrderAddRequest request) {
        if (SaleOrderOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            List<Long> mateInventoryIdList = CollUtil.getFieldValues(request.getItem(), "mateInventoryId", Long.class);
            List<MateInventoryDetailInfo> mateInventoryDetailInfos = mateInventoryFacade.listMateInventoryByIdList(mateInventoryIdList);
            Map<Long, MateInventoryDetailInfo> idGroup = mateInventoryDetailInfos.stream().collect(Collectors.toMap(MateInventoryDetailInfo::getId, Function.identity()));
            for (SaleDetailOrderAddRequest saleDetailOrderAddRequest : request.getItem()) {
                MateInventoryDetailInfo mateInventoryDetailInfo = idGroup.get(saleDetailOrderAddRequest.getMateInventoryId());
                if (ObjectUtil.isEmpty(mateInventoryDetailInfo) || mateInventoryDetailInfo.getAvailableQty() < saleDetailOrderAddRequest.getOutQty()){
                    throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法锁定");
                }
            }
        }
        request.setCreateUserName(SPRequestContextHolder.getCurrentSystemUserRealName());
        request.setCreateUserCode(SPRequestContextHolder.getCurrentSystemUserLoginName());
        request.setOrderTime(new Date());
        request.setOrderType(SaleOrderOrderTypeEnum.T3.getIntValue());
        SubWarehouseInfo subWarehouse = subWarehouseFacade.getSubWarehouseByCode(request.getSubWarehouseCode());
        request.setSubWarehouseName(subWarehouse.getSubWarehouseName());
        if (StrUtil.isNotBlank(request.getAccount())) {
            CompanyAndBankInfo companyAndBankInfo = accountFacade.queryCompanyByAccount(request.getAccount());
            request.setBank(companyAndBankInfo.getBank());
            request.setSettleCompanyCode(companyAndBankInfo.getSettleCompanyCode());
            request.setSettleCompanyName(companyAndBankInfo.getSettleCompanyName());
        }
        CurrencyInfo currency = mdmComponent.getCurrency(request.getCurrencyCode());
        request.setExchangeRate(currency.getUsdRate());
        SaleOrderAddResponse response = saleOrderFacade.addSaleOrder(request);
        if (SaleOrderOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            saleOrderManager.saleApply(response.getSaleDetailOrderInfoList());
        }
        return succeed();
    }

    @Operation(summary = "分页查询")
    @GetMapping("/saleOrder/pageQuery")
    public CommonResponse<List<SaleOrderPageQueryModel>> pageQuerySaleOrder(SaleOrderQueryRequest request) {
        return succeedWithPage(saleOrderFacade.pageQuerySaleOrder(request));
    }

    @Operation(summary = "销售单导出Excel")
    @GetMapping("/saleOrder/export")
    public CommonResponse<ExportInfo> exportSaleOrder(SaleOrderQueryRequest request) {
        return succeedWith(exportManager.exportSaleOrder(request));
    }

    @Operation(summary = "货品模式切换销售单分页查询")
    @GetMapping("/saleOrder/pageSaleOrderModeQuery")
    public CommonResponse<List<SaleOrderModeQueryModel>> pageSaleOrderModeQuery(SaleOrderModeQueryRequest request) {
        Page<SaleOrderModeQueryModel> saleOrderModeQueryModelPage = saleOrderFacade.pageSaleOrderModeQuery(request);
        return succeedWithPage(saleOrderModeQueryModelPage);
    }

    @Operation(summary = "销售单货品模式导出Excel")
    @GetMapping("/saleOrder/exportGoodsMode")
    public CommonResponse<ExportInfo> exportSaleOrderGoodsMode(SaleOrderModeQueryRequest request) {
        return succeedWith(exportManager.exportSaleOrderGoodsMode(request));
    }


    @Operation(summary = "删除")
    @DeleteMapping("/saleOrder/delete/{id}")
    public CommonResponse deleteSaleOrder(@PathVariable("id") Long id) {
        saleOrderFacade.deleteSaleOrder(id);
        return succeed();
    }

    @Operation(summary = "详情查询")
    @GetMapping("/saleOrder/get/{id}")
    public CommonResponse<SaleOrderDetailResponse> getSaleOrderById(@PathVariable("id") Long id) {
        SaleOrderDetailResponse response = saleOrderFacade.getSaleOrderById(id);
        SubWarehouseInfo subWarehouseInfo = subWarehouseFacade.getSubWarehouseByCode(response.getMain().getSubWarehouseCode());
        List<Long> mateInventoryIds = CollUtil.getFieldValues(response.getItem(), "mateInventoryId", Long.class);
        List<MateInventoryDetailInfo> mateInventoryDetailInfos = mateInventoryFacade.listMateInventoryByIdList(mateInventoryIds);
        Map<Long, MateInventoryDetailInfo> map = new HashMap<>();
        for (MateInventoryDetailInfo mateInventoryDetailInfo : mateInventoryDetailInfos) {
            map.put(mateInventoryDetailInfo.getId(), mateInventoryDetailInfo);
        }
        for (SaleDetailOrderModel saleDetailOrderModel : response.getItem()) {
            MateInventoryDetailInfo mateInventoryDetailInfo = map.get(saleDetailOrderModel.getMateInventoryId());
            if (ObjectUtil.isNotEmpty(mateInventoryDetailInfo)) {
                saleDetailOrderModel.setAvailableQty(mateInventoryDetailInfo.getAvailableQty());
                saleDetailOrderModel.setCostPrice(mateInventoryDetailInfo.getCostPrice());
                saleDetailOrderModel.setExpireDate(mateInventoryDetailInfo.getExpireDate());
            }
        }
        response.getMain().setWarehouseCode(subWarehouseInfo.getWarehouseCode());
        response.getMain().setWarehouseName(subWarehouseInfo.getWarehouseName());
        return succeedWith(response);
    }


    @Operation(summary = "修改")
    @PutMapping("/saleOrder/update")
    public CommonResponse updateSaleOrder(@RequestBody @Validated SaleOrderUpdateRequest request) {
        if (StrUtil.isNotBlank(request.getAccount())) {
            CompanyAndBankInfo companyAndBankInfo = accountFacade.queryCompanyByAccount(request.getAccount());
            request.setBank(companyAndBankInfo.getBank());
            request.setSettleCompanyCode(companyAndBankInfo.getSettleCompanyCode());
            request.setSettleCompanyName(companyAndBankInfo.getSettleCompanyName());
        }
        if (SaleOrderOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            List<Long> mateInventoryIdList = CollUtil.getFieldValues(request.getItem(), "mateInventoryId", Long.class);
            List<MateInventoryDetailInfo> mateInventoryDetailInfos = mateInventoryFacade.listMateInventoryByIdList(mateInventoryIdList);
            Map<Long, MateInventoryDetailInfo> idGroup = mateInventoryDetailInfos.stream().collect(Collectors.toMap(MateInventoryDetailInfo::getId, Function.identity()));
            for (SaleDetailOrderAddRequest saleDetailOrderAddRequest : request.getItem()) {
                MateInventoryDetailInfo mateInventoryDetailInfo = idGroup.get(saleDetailOrderAddRequest.getMateInventoryId());
                if (ObjectUtil.isEmpty(mateInventoryDetailInfo) || mateInventoryDetailInfo.getAvailableQty() < saleDetailOrderAddRequest.getOutQty()){
                    throw new BusinessException(CommonRespCode.SYSTEM_ERR, "可用库存不足，无法锁定");
                }
            }
        }
        SubWarehouseInfo subWarehouse = subWarehouseFacade.getSubWarehouseByCode(request.getSubWarehouseCode());
        request.setSubWarehouseName(subWarehouse.getSubWarehouseName());
        CurrencyInfo currency = mdmComponent.getCurrency(request.getCurrencyCode());
        request.setExchangeRate(currency.getUsdRate());
        saleOrderFacade.updateSaleOrder(request);
        if (SaleOrderOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            SaleOrderDetailResponse response = saleOrderFacade.getSaleOrderById(request.getId());
            saleOrderManager.saleApply(response.getItem());
        }
        return succeed();
    }

    @Operation(summary = "修改订单状态")
    @PutMapping("/saleOrder/setOrderStatus")
    public CommonResponse updateSaleOrderStatus(@RequestBody @Validated SaleOrderUpdateStatusRequest request) {
        saleOrderFacade.updateStatus(request);
        if (SaleOrderOrderStatusEnum.S3.eq(request.getOrderStatus())) {
            SaleOrderDetailResponse response = saleOrderFacade.getSaleOrderById(request.getId());
            saleOrderManager.saleApplyPass(response.getMain(), response.getItem());
            //创建代办事项
            try {
                SystemTodoAddRequest addRequest = new SystemTodoAddRequest();
                addRequest.setRoleName(commonProperties.getLogisticsRoleName());
                addRequest.setTodoType(SystemTodoTodoTypeEnum.T5.getIntValue());
                addRequest.setDataId(response.getMain().getOrderNo());
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("orderNo", response.getMain().getOrderNo());
                addRequest.setTodoMessage(jsonObject.toJSONString());
                systemTodoFacade.addSystemTodo(addRequest);
            } catch (Exception e) {
                log.error("生成待办失败", e);
            }
        }
        return succeed();
    }

    @Operation(summary = "导入")
    @PostMapping("/saleOrder/import")
    public CommonResponse<List<SaleOrderImportInfo>> importSaleOrder(
            @RequestParam("subWarehouseCode") String subWarehouseCode,
            @RequestParam("saleSubChannel") String saleSubChannel,
            @RequestParam("file") MultipartFile file) {
        if (StringUtils.isBlank(subWarehouseCode) || StringUtils.isBlank(saleSubChannel)) {
            throw new BusinessException(CommonRespCode.PARAM_ERR, "请先选择仓库和渠道");
        }
        return succeedWith(saleOrderManager.importSaleOrder(subWarehouseCode, saleSubChannel, file));
    }

    @Operation(summary = "撤回")
    @GetMapping("/saleOrder/cancelOrder/{id}")
    @Transactional(rollbackFor = Exception.class)
    public CommonResponse cancelSaleOrder(@PathVariable("id") Long id) {
        SaleOrderDetailResponse saleOrderDetailResponse = saleOrderFacade.getSaleOrderById(id);
        SaleOrderInfo main = saleOrderDetailResponse.getMain();
        if (!(main.getOrderStatus().equals(SaleOrderOrderStatusEnum.S2.getIntValue()) || main.getOrderStatus().equals(SaleOrderOrderStatusEnum.S3.getIntValue()))) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前状态不可以撤回");
        }
        // 如果订单状态是3 撤回则需要先 删除待出申请，然后释放库存，然后更新为草稿
        if (main.getOrderStatus().equals(SaleOrderOrderStatusEnum.S3.getIntValue())) {
            LogisticsTraceApplyDeleteRequest deleteRequest = new LogisticsTraceApplyDeleteRequest();
            deleteRequest.setSourceOrderNo(main.getOrderNo());
            deleteRequest.setSourceOrderType(SubjectEnum.T42.getCode());
            deleteRequest.setSourceDetailOrderNoList(saleOrderDetailResponse.getItem().stream().map(SaleDetailOrderInfo::getDetailOrderNo).collect(Collectors.toList()));
            try {
                logisticsTraceApplyOrderFacade.deleteLogisticsTraceApply(deleteRequest);
            } catch (Exception e) {
                log.error("待出申请删除失败", e);
                throw new BusinessException(CommonRespCode.PARAM_ERR, "待出申请删除失败");
            }
        }
        List<SaleDetailOrderInfo> saleDetailOrderInfoList = new ArrayList<>();
        saleOrderDetailResponse.getItem().forEach(item -> {
            SaleDetailOrderInfo saleDetailOrderInfo = BeanUtil.copyProperties(item, SaleDetailOrderInfo.class);
            saleDetailOrderInfoList.add(saleDetailOrderInfo);
        });
        // 释放库存
        saleOrderManager.saleOrderRelease(saleDetailOrderInfoList);
        // 改状态
        SaleOrderUpdateStatusRequest update = new SaleOrderUpdateStatusRequest();
        update.setId(id);
        update.setOrderStatus(SaleOrderOrderStatusEnum.S1.getIntValue());
        this.updateSaleOrderStatus(update);
        return succeed();
    }

    @Operation(summary = "审批拒绝")
    @GetMapping("/saleOrder/refuse/{id}")
    public CommonResponse saleOrderRefuse(@PathVariable("id") Long id) {
        SaleOrderDetailResponse saleOrderDetailResponse = saleOrderFacade.getSaleOrderById(id);
        SaleOrderInfo main = saleOrderDetailResponse.getMain();
        if (!main.getOrderStatus().equals(SaleOrderOrderStatusEnum.S2.getIntValue())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前状态不可以拒绝审批");
        }
        List<SaleDetailOrderInfo> saleDetailOrderInfoList = new ArrayList<>();
        saleOrderDetailResponse.getItem().forEach(item -> {
            SaleDetailOrderInfo saleDetailOrderInfo = BeanUtil.copyProperties(item, SaleDetailOrderInfo.class);
            saleDetailOrderInfoList.add(saleDetailOrderInfo);
        });
        // 释放库存
        saleOrderManager.saleOrderRelease(saleDetailOrderInfoList);
        // 改状态
        SaleOrderUpdateStatusRequest update = new SaleOrderUpdateStatusRequest();
        update.setId(id);
        update.setOrderStatus(SaleOrderOrderStatusEnum.S1.getIntValue());
        this.updateSaleOrderStatus(update);
        return succeed();
    }

}
